// ============================================================================
//
// Copyright (C) 2006-2007 Dengues
//
// Google Group: http://groups.google.com/group/dengues
// QQ Group: 24885404
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// ============================================================================
package org.dengues.designer.ui.properties;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.dengues.core.components.ENodeParameterName;
import org.dengues.core.components.NodePropertyParameter;
import org.dengues.core.process.CompElement;
import org.dengues.core.process.ICompNode;
import org.dengues.core.property.EPropertyCategory;
import org.dengues.core.property.NodeParameterUtils;
import org.dengues.designer.ui.database.parts.DBColumnEditPart;
import org.dengues.designer.ui.database.parts.DBNoteEditPart;
import org.dengues.designer.ui.database.parts.DBTableEditPart;
import org.dengues.designer.ui.database.parts.ForeignKeyEditPart;
import org.dengues.designer.ui.editors.DatabaseMultiEditor;
import org.dengues.designer.ui.editors.ProcessMultiEditor;
import org.dengues.designer.ui.process.models.CompBlock;
import org.dengues.designer.ui.process.models.CompConnection;
import org.dengues.designer.ui.process.models.CompNode;
import org.dengues.designer.ui.process.parts.CompConnectionPart;
import org.dengues.designer.ui.process.parts.CompNodePart;
import org.dengues.designer.ui.properties.controllers.AbstractPropertyController;
import org.dengues.designer.ui.properties.generators.DynamicPropertyGenerators;
import org.dengues.model.database.AbstractDBObject;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.commands.CommandStack;
import org.eclipse.gef.editparts.AbstractGraphicalEditPart;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.MultiPageEditorPart;
import org.eclipse.ui.views.properties.tabbed.AbstractPropertySection;
import org.eclipse.ui.views.properties.tabbed.ITabbedPropertyConstants;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetWidgetFactory;

/**
 * Qiang.Zhang.Adolf@gmail.com class global comment. Detailled comment <br/>
 * 
 * $Id: Dengues.epf Qiang.Zhang.Adolf@gmail.com 2008-1-15 qiang.zhang $
 * 
 */
public class PropertyTabDynamicSection extends AbstractPropertySection {

    protected EPropertyCategory category;

    protected MultiPageEditorPart part;

    protected CompElement elem;

    protected AbstractGraphicalEditPart child;

    protected Composite composite;

    protected String currentComponent;

    protected String currentChild;

    private final DynamicPropertyGenerators generators = DynamicPropertyGenerators.getInstance();

    private TabbedPropertySheetWidgetFactory widgetFactory;

    private final Map<String, Object> curControlMap;

    /**
     * Qiang.Zhang.Adolf@gmail.com PropertyTabDynamicSection constructor comment.
     * 
     * @param category
     */
    public PropertyTabDynamicSection(EPropertyCategory category) {
        super();
        this.category = category;
        curControlMap = new HashMap<String, Object>();
    }

    public PropertyTabDynamicSection(EPropertyCategory category, TabbedPropertySheetWidgetFactory widgetFactory) {
        this(category);
        this.widgetFactory = widgetFactory;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.views.properties.tabbed.AbstractPropertySection#setInput(org.eclipse.ui.IWorkbenchPart,
     * org.eclipse.jface.viewers.ISelection)
     */
    @Override
    public void setInput(IWorkbenchPart part, ISelection selection) {
        if (!(selection instanceof StructuredSelection)) {
            return;
        }

        IWorkbenchPart activeEditor = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor();
        if (part == null) {
            part = activeEditor;
        }
        if (part instanceof ProcessMultiEditor) {
            this.part = (ProcessMultiEditor) part;
        } else if (part instanceof DatabaseMultiEditor) {
            this.part = (DatabaseMultiEditor) part;
        }
        super.setInput(this.part, selection);
        Object element = ((StructuredSelection) selection).getFirstElement();
        if (element instanceof DBNoteEditPart) {
            return;
        }

        if (element instanceof CompNodePart || element instanceof CompConnectionPart) {
            if (element instanceof CompNodePart) {
                Object model = ((CompNodePart) element).getModel();
                if (model instanceof CompNode) {
                    elem = (CompNode) model;
                }
                if (model instanceof CompBlock) {
                    elem = (CompBlock) model;
                }
            } else if (element instanceof CompConnectionPart) {
                elem = (CompConnection) ((CompConnectionPart) element).getModel();
            }
            if (elem != null) {
                if (currentComponent == null) {
                    addComponents(true);
                } else {
                    if (!currentComponent.equals(elem.getCompName())) {
                        addComponents(true);
                    } else {
                        refresh();
                    }
                }
                currentComponent = elem.getCompName();
            }
        } else {
            if (element instanceof DBTableEditPart) {
                child = (DBTableEditPart) element;
            } else if (element instanceof DBColumnEditPart) {
                child = (DBColumnEditPart) element;
            } else if (element instanceof ForeignKeyEditPart) {
                child = (ForeignKeyEditPart) element;
            }
            if (currentChild == null) {
                addComponents(true);
            } else {
                if (!currentChild.equals(((AbstractDBObject) child.getModel()).getName())) {
                    addComponents(true);
                } else {
                    refresh();
                }
            }
            if (child == null) {
                return;
            }
            currentChild = ((AbstractDBObject) child.getModel()).getName();
        }
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "addComponents".
     * 
     * @param force
     */
    public void addComponents(boolean force) {
        if (force) {
            if ((currentComponent != null || currentChild != null) && composite != null && !composite.isDisposed()) {
                Control[] ct = composite.getChildren();
                for (int i = 0; i < ct.length; i++) {
                    ct[i].dispose();
                }
            }
        }

        generators.initController(this);
        List<NodePropertyParameter> elementParameters = null;
        if (elem != null) {
            elementParameters = elem.getElementParameters();
        } else {
            if (child instanceof DBTableEditPart) {
                elementParameters = ((DBTableEditPart) child).getPropParameters();
            } else if (child instanceof DBColumnEditPart) {
                elementParameters = ((DBColumnEditPart) child).getPropParameters();
            }
        }
        if (elementParameters == null) {
            return;
        }
        Map<Integer, List<NodePropertyParameter>> numCols = new HashMap<Integer, List<NodePropertyParameter>>();
        Integer maxNum = 0;
        for (NodePropertyParameter nodePropParam : elementParameters) {
            int nbRow = nodePropParam.getNbRow();
            if (nbRow > maxNum) {
                maxNum = nbRow;
            }
            if (!numCols.containsKey(nbRow)) {
                List<NodePropertyParameter> subParameters = new ArrayList<NodePropertyParameter>();
                subParameters.add(nodePropParam);
                numCols.put(nbRow, subParameters);
            } else {
                List<NodePropertyParameter> integer = numCols.get(nbRow);
                integer.add(nodePropParam);
                numCols.put(nbRow, integer);
            }
        }
        for (int i = 0; i <= maxNum; i++) {
            List<NodePropertyParameter> list = numCols.get(new Integer(i));
            if (list != null) {
                int cols = 0;
                for (NodePropertyParameter parameter2 : list) {
                    if (parameter2.getPropertyCategory() == category && parameter2.isShow()) {
                        cols++;
                    }
                }
                if (cols == 0) {
                    continue;
                }
                Composite subcomposite = new Composite(composite, SWT.NONE);
                GridLayout gridLayout = new GridLayout(cols, false);
                gridLayout.marginBottom = 0;
                gridLayout.marginHeight = 0;
                gridLayout.marginLeft = 0;
                gridLayout.marginRight = 0;
                gridLayout.marginTop = 0;
                gridLayout.marginWidth = 0;
                subcomposite.setLayout(gridLayout);
                subcomposite.setLayoutData(new GridData(GridData.FILL_BOTH));
                subcomposite.setBackground(composite.getBackground());
                for (NodePropertyParameter parameter2 : list) {
                    if (parameter2.getPropertyCategory() == category && parameter2.isShow()) {
                        Control lastControl = null;
                        AbstractPropertyController controller = generators.getController(parameter2.getFieldCategory());
                        lastControl = controller.createControl(subcomposite, parameter2, lastControl);
                        if (parameter2.getName().equals(ENodeParameterName.CONNECTIVITY.getName())) {
                            controller.updateComponentVisiable();
                        }
                    }
                }
            }
        }
        if (this.elem instanceof ICompNode) {
            ICompNode node = (ICompNode) this.elem;
            changeTablePropertyValue(node);
        }
        // if (connectivityController != null) {
        // connectivityController.updateComponentVisiable();
        // }
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "changeTablePropertyValue".
     * 
     * @param node
     */
    private void changeTablePropertyValue(ICompNode node) {
        List<NodePropertyParameter> list = NodeParameterUtils.changeTablePropertyValue(node, true);
        for (NodePropertyParameter nodePropertyParameter : list) {
            ((TableViewer) getCurControlMap().get(nodePropertyParameter.getName())).refresh();
        }
        if (!list.isEmpty()) {
            CommandStack stack = (CommandStack) this.part.getAdapter(CommandStack.class);
            stack.execute(new Command() {
            });
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.views.properties.tabbed.AbstractPropertySection#refresh()
     */
    @Override
    public void refresh() {
        composite.getParent().layout(true, true);
    }

    @Override
    public void createControls(Composite parent, TabbedPropertySheetPage tabbedPropertySheetPage) {
        super.createControls(parent, tabbedPropertySheetPage);
        composite = parent;
        GridLayout layout = new GridLayout();
        layout.marginWidth = ITabbedPropertyConstants.HSPACE + 2;
        layout.marginHeight = ITabbedPropertyConstants.VSPACE;
        composite.setLayout(layout);
        // GridData data = new GridData(GridData.FILL_BOTH);
        // composite.setLayoutData(data);
    }

    /**
     * Getter for elem.
     * 
     * @return the elem
     */
    public Object getElem() {
        if (elem != null) {
            return this.elem;
        } else if (child != null) {
            return child;
        }
        return null;
    }

    /**
     * Getter for part.
     * 
     * @return the part
     */
    public MultiPageEditorPart getCurrentEditor() {
        return this.part;
    }

    /**
     * Getter for composite.
     * 
     * @return the composite
     */
    public Composite getComposite() {
        return this.composite;
    }

    /**
     * Getter for child.
     * 
     * @return the child
     */
    public AbstractGraphicalEditPart getChildEditPart() {
        return this.child;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.ui.views.properties.tabbed.AbstractPropertySection#getWidgetFactory()
     */
    @Override
    public TabbedPropertySheetWidgetFactory getWidgetFactory() {
        if (widgetFactory != null) {
            return widgetFactory;
        }
        return super.getWidgetFactory();
    }

    /**
     * Getter for curControlMap.
     * 
     * @return the curControlMap
     */
    public Map<String, Object> getCurControlMap() {
        return this.curControlMap;
    }

}
